package net.lainiao.zhihu.common;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 我的页面分页实现
 */
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class MyPageInterceptor implements Interceptor {
    /**
     * 数据源类型
     */
    private String dataType;
    /**
     * 拦截规则
     */
    private String regular;

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public void setRegular(String regular) {
        this.regular = regular;
    }

    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY);
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        // 配置文件中SQL语句的ID
        String id = mappedStatement.getId();
        if(id.matches(regular)) {
            if(dataType.equals("mysql")){
                getMySqlPage(invocation.getArgs()[0], statementHandler, metaObject);
            }
        }
        return invocation.proceed();
    }

    /**
     * 对Mysql类型的分页
     * @param o
     * @param statementHandler
     * @param metaObject
     * @throws SQLException
     */
    private void getMySqlPage(Object o, StatementHandler statementHandler, MetaObject metaObject) throws SQLException {
        BoundSql boundSql = statementHandler.getBoundSql();
        // 原始的SQL语句
        String sql = boundSql.getSql();
        // 查询总条数的SQL语句
        String countSql = "select count(*) from (" + sql + ")a";
        Connection connection = (Connection) o;
        PreparedStatement countStatement = connection.prepareStatement(countSql);
        ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
        parameterHandler.setParameters(countStatement);
        ResultSet rs = countStatement.executeQuery();
        MyPage page = (MyPage)boundSql.getParameterObject();
        if(rs.next()) {
            page.setTotal(rs.getInt(1));
        }
        // 改造后带分页查询的SQL语句
        String pageSql = sql + " limit " + page.getLimitStart() + "," + page.getPageSize();
        System.out.println("分页后Sql:"+pageSql);
        metaObject.setValue("delegate.boundSql.sql", pageSql);
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {

    }
}
